package cmm.Seman;

import cmm.Parser.TreeNode;

import java.util.LinkedList;
import java.util.Objects;

/**
 * Created by Iray on 2017/12/1.
 */
public class SymbolTable {

    private LinkedList<Symbol> symbolLinkedList;

    private static final String TEMP_PREFIX = "*temp";
    private static LinkedList<Symbol> tempNames;
    private static SymbolTable symbolTable;

    private SymbolTable() {
        symbolLinkedList = new LinkedList<Symbol>();
    }

    public static SymbolTable getSymbolTable() {
        if(symbolTable == null){
            symbolTable = new SymbolTable();
            tempNames = new LinkedList<>();
        }
        return symbolTable;
    }

    public void deleteTable() {
        symbolTable = null;
    }

    public void registe(Symbol symbol) throws Exception {
        for(int i = 0; i < symbolLinkedList.size(); i++) {
            if(symbolLinkedList.get(i).getName().equals(symbol.getName()) ) {
                if(symbolLinkedList.get(i).getLevel() < symbol.getLevel()) {
                    symbol.setSameName(symbolLinkedList.get(i));
                    symbolLinkedList.set(i, symbol);
                    return;
                }else {
                    throw new Exception(symbol.getName() + " already exists");
                }
            }
        }
        symbolLinkedList.add(symbol);
    }

    public void unregiste(int level) {
        for (int i=0; i<symbolLinkedList.size(); i++) {
            if (symbolLinkedList.get(i).getLevel() == level) {
                symbolLinkedList.set(i, symbolLinkedList.get(i).getSameName());
            }
        }
        for (int i=symbolLinkedList.size()-1 ; i>=0; i--) {
            if (symbolLinkedList.get(i) == null) {
                symbolLinkedList.remove(i);
            }
        }
    }

    public int findPosition(String symbolName) throws Exception {
        for(int i = 0; i< symbolLinkedList.size();i++){
            if(Objects.equals(symbolLinkedList.get(i).getName(), symbolName))
                return i;
        }

        throw new Exception("no such symbol name");
    }

    public boolean setValue(String symbolName, Value value) throws Exception {
        for(int i = 0; i< symbolLinkedList.size();i++){
            if(Objects.equals(symbolLinkedList.get(i).getName(), symbolName)) {
                symbolLinkedList.get(i).setValue(value);
                return true;
            }
        }

        return false;
    }
    public void setValue(String symbolName, int idx, int value) throws Exception {
        for(int i = 0; i< symbolLinkedList.size();i++){
            if(Objects.equals(symbolLinkedList.get(i).getName(), symbolName)) {
                symbolLinkedList.get(i).getValue().setIlValue(idx, value);
                return;
            }
        }

        throw new Exception("no such symbol name");
    }
    public void setValue(String symbolName, int idx, double value) throws Exception {
        for(int i = 0; i< symbolLinkedList.size();i++){
            if(Objects.equals(symbolLinkedList.get(i).getName(), symbolName)) {
                symbolLinkedList.get(i).getValue().setDlValue(idx, value);
                return;
            }
        }

        throw new Exception("no such symbol name");
    }

    public Value findValue(String symbolName) throws Exception {
        for(int i = 0; i< symbolLinkedList.size();i++){
            if(Objects.equals(symbolLinkedList.get(i).getName(), symbolName))
                return symbolLinkedList.get(i).getValue();
        }

        throw new Exception("no such symbol name");
    }

    public int getType(String name) {
        for(Symbol tr: symbolLinkedList) {
            if(tr.getName().equals(name))
                return tr.getType();
        }
            return -1;
    }

    public Symbol getTempSymbol() {
        String temp = null;
        for (int i = 1; ; i++) {
            temp = TEMP_PREFIX + i;
            boolean exist = false;
            for (Symbol s : tempNames) {
                if (s.getName().equals(temp)) {
                    exist = true;
                    break;
                }
            }
            for (Symbol s : symbolLinkedList) {
                if (s.getName().equals(temp)) {
                    exist = true;
                    break;
                }
            }
            if (exist) {
                continue;
            }
            Symbol s = new Symbol(temp, Symbol.TEMP, -1);
            tempNames.add(s);
            return s;
        }
    }

}
